#include "Object.h"
#include "vertex.h"
#include "Camera.h"
#include <string.h>

Object::Object(void)
{
	m_position = Vector3(0.0f, 0.0f, 0.0f);
	m_rotateAngle = Vector3(0.0f, 0.0f, 0.0f);
	m_scale = Vector3(1.0f, 1.0f, 1.0f);
	m_texture = NULL;
	m_model = NULL;
	m_shader = NULL;
	CalWorldMatrix();
}

Object::~Object(void)
{

}

void Object::Init(const char* id, const Vector3 &position, const Vector3 &rotateAngle, const Vector3 &scale, Texture* const &texture, Model* const &model, Shader* const &shader)
{
	strcpy(m_id, id);
	m_position = position;
	m_rotateAngle = rotateAngle;
	m_scale = scale;
	m_texture = texture;
	m_model = model;
	m_shader = shader;
	CalWorldMatrix();
}

void Object::Draw(const Matrix &viewProjectMatrix)
{
	m_wvpMatrix = m_worldMatrix * viewProjectMatrix;

	m_shader->EnableState();
	glUseProgram(m_shader->program);

	glBindBuffer(GL_ARRAY_BUFFER, m_model->GetVboID());
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_model->GetIboID());

	if(m_shader->a_position != -1)
	{
		glEnableVertexAttribArray(m_shader->a_position);
		glVertexAttribPointer(m_shader->a_position, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *) offsetof(Vertex, pos));
	}

	if(m_shader->a_uv != -1)
	{
		glEnableVertexAttribArray(m_shader->a_uv);
		glVertexAttribPointer(m_shader->a_uv, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *) offsetof(Vertex, uv));
	}

	if (m_shader->u_color != -1)
	{
		glUniform4f(m_shader->u_color, m_color.x, m_color.y, m_color.z, m_color.w);
	}

	if (m_shader->u_matrix != -1)
	{
		glUniformMatrix4fv(m_shader->u_matrix, 1, GL_FALSE, (GLfloat *) &m_wvpMatrix);
	}
	
	if(m_shader->a_CubeVertexPos != -1)
	{
		glEnableVertexAttribArray(m_shader->a_CubeVertexPos);
		glVertexAttribPointer(m_shader->a_CubeVertexPos, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *) offsetof(Vertex, pos));
	}

	if (m_shader->u_CubeMVPMatrix != -1)
	{
		glUniformMatrix4fv(m_shader->u_CubeMVPMatrix, 1, GL_FALSE, (GLfloat *) &m_wvpMatrix);
	}

	//===================================
	unsigned short textureUnit = 0;
	 
	// make active a texture unit
	glActiveTexture(GL_TEXTURE0 + textureUnit);
	
	// bind the texture to the currently active texture unit
	glBindTexture(m_texture->GetTarget(), m_texture->GetTextureID());
	 
	// set the uniform sampler
	if (m_shader->u_sample != -1)
	{
		glUniform1i(m_shader->u_sample, textureUnit);
	}

	if (m_shader->u_samplerCubeMap != -1)
	{
		glUniform1i(m_shader->u_samplerCubeMap, 0);
	}
	
	//int nBufferSize = 0;
	//glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &nBufferSize);
	//int numOfIndices = (nBufferSize / sizeof(unsigned short));
	
	glDrawElements(GL_TRIANGLES, m_model->GetNumOfIndices(), GL_UNSIGNED_SHORT, 0);
	
	glBindTexture(m_texture->GetTarget(), 0);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

	m_shader->DisableState();
	
	//textureUnit++;
	//===================================
}

void Object::Update()
{
	
}

void Object::SetPosition(Vector3 position)
{
	m_position = position;
	CalWorldMatrix();
}

void Object::SetRotateAngle(Vector3 rotateAngle)
{
	m_rotateAngle = rotateAngle;
	CalWorldMatrix();
}

void Object::SetScale(Vector3 scale)
{
	m_scale = scale;
	CalWorldMatrix();
}

void Object::SetTexture(Texture *texture)
{
	m_texture = texture;
}

void Object::SetModel(Model *model)
{
	m_model = model;
}

void Object::SetShader(Shader *shader)
{
	m_shader = shader;
}

void Object::CalWorldMatrix()
{
	Matrix scaleMatrix;
	scaleMatrix.SetScale(m_scale);

	Matrix rotateMatrix;
	rotateMatrix.SetRotation(m_rotateAngle);

	Matrix translateMatrix;
	translateMatrix.SetTranslation(m_position);

	m_worldMatrix = scaleMatrix * rotateMatrix * translateMatrix;
}

const char* Object::GetID()
{
	return m_id;
}